package com.oauth2.config;

import com.alibaba.fastjson.JSON;
import com.oauth2.constant.Constants;
import com.oauth2.filter.OAuth2AuthenticationFilter;
import com.oauth2.util.CookieUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.ResponseEntity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author shipeilei
 * @date 2020-7-16 17:53:31
 * @desc desc
 */
@Configuration
@EnableResourceServer
public class OAuth2ResourceServer extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                //无需登录验证，要放在前面
                .antMatchers("/resources/**", "/oauth/**", "/login", "/handleLogin").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
                //监听登出方法，触发登出逻辑，删除登录Cookie
                .logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler()).deleteCookies(Constants.COOKIE_TOKEN_KEY)
                .permitAll()
                .and().csrf().disable()
                //自定义过滤器先与oauth2过滤器设置
                .addFilterBefore(new OAuth2AuthenticationFilter(), AbstractPreAuthenticatedProcessingFilter.class);
    }

    /**
     * 自定义登出逻辑
     */
    @Bean
    @ConditionalOnMissingBean
    public LogoutSuccessHandler logoutSuccessHandler() {
        return new LogoutSuccessHandler() {
            @Autowired
            private TokenStore tokenStore;
            @Override
            public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
                String accessToken = CookieUtil.getCookieValue(request, Constants.COOKIE_TOKEN_KEY);
                if (!StringUtils.isEmpty(accessToken)) {
                    OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(accessToken);
                    if (null != oAuth2AccessToken) {
                        tokenStore.removeAccessToken(oAuth2AccessToken);
                        OAuth2RefreshToken oAuth2RefreshToken = oAuth2AccessToken.getRefreshToken();
                        if (null != oAuth2RefreshToken) {
                            tokenStore.removeRefreshToken(oAuth2RefreshToken);
                            tokenStore.removeAccessTokenUsingRefreshToken(oAuth2RefreshToken);
                        }
                    }
                }
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().write(JSON.toJSONString(ResponseEntity.ok("退出成功")));
            }
        };
    }

    /**
     * 自定义个一个authenticationEntryPoint，实现如果无访问权限跳转到登录页面
     * @return
     */
    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return (request, response, e) -> response.sendRedirect("/login");
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        //定义客户端的资源及设置无访问权限跳转检查点
        resources.resourceId("user-services").authenticationEntryPoint(authenticationEntryPoint());
    }

}
